#pragma once

#include <string>
#include <memory>
#include "Socket.hpp"
#include "NetCal.hpp"

using namespace socket_ns;

class Client
{
public:
    Client(const std::string &ip, const uint16_t &port)
        : _ip(ip), _port(port), _client_sockfd(std::make_shared<TcpSocket>())
    {
    }
    ~Client()
    {
    }

    void Init()
    {
        if (_client_sockfd->BuildConnectorSocket(_ip, _port))
        {
            std::cout << "连接成功" << std::endl;
        }
        else
        {
            std::cout << "连接失败" << std::endl;
        }
    }

    void Start()
    {
        std::string packagestreamqueue;
        while (true)
        {
            // 输入数据
            std::cout << "Please enter:";
            std::string message;
            getline(std::cin, message);

            // 1. 得到请求数据
            auto req = Factory::BuildRequestDefault();
            req->Analysis(message);

            // 2. 序列化请求
            std::string jsonstr;
            req->Serialize(&jsonstr);

            // 3. 添加报头
            jsonstr = Encode(jsonstr);

            // 4. 发送数据
            int n = _client_sockfd->Send(jsonstr);

            if (n <= 0)
            {
                std::cout << "Send message failed" << std::endl;
                continue;
            }

            while (true)
            {
                 // 5. 接收应答
                std::string tail;
                ssize_t n = _client_sockfd->Recv(&tail);
                packagestreamqueue += tail;
                if (n <= 0)
                {
                    break;
                }
                // 我们能保证我们读到的是一个完整的报文吗？不能！
                // 6. 报文解析，提取报头和有效载荷
                std::string package = Decode(packagestreamqueue);
                if (package.empty())
                    continue;

                // std::cout << "package: \n"
                //           << package << std::endl;

                // 6. 反序列化
                auto resp = Factory::BuildResponseDefault();
                resp->DeSerialize(package);

                // 7. 打印结果
                resp->PrintResult();

                break;
            }

        }
    }

    void Close()
    {
        _client_sockfd->Close();
    }

private:
    std::string _ip;
    uint16_t _port;
    SockPtr _client_sockfd;
};